﻿using CookComputing.XmlRpc;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Text;

namespace Rarous.TexyNet.Providers
{
    /// <summary>
    /// Xml rpc texy provider
    /// </summary>
    public class XmlRpcTexyProvider : TexyProvider
    {
        #region Constants
        private const string DefaultXmlRpcUrl = "http://xmlrpc.texy.info/";
        #endregion

        #region Fields
        private ITexyConverter texyConverter;
        #endregion

        #region Properties
        /// <summary>
        /// 
        /// </summary>
        protected ITexyConverter TexyConverter
        {
            get
            {
                if (texyConverter == null)
                {
                    texyConverter = XmlRpcProxyGen.Create<ITexyConverter>();
                    texyConverter.Url = DefaultXmlRpcUrl;
                }
                return texyConverter;
            }
        }
        #endregion

        #region Private methods
        /// <summary>
        /// Převádí objekt konfigurace na XmlRpc strukturu
        /// </summary>
        /// <returns>Vrací XmlRpcStruct naplněný informacemi o konfiguraci Texy!</returns>
        private static XmlRpcStruct GetConfigurationStruct(ITexySettings settings)
        {
            XmlRpcStruct s = new XmlRpcStruct();

            if (settings == null)
            {
                return s;
            }

            s.Add("safeMode", settings.SafeMode);
            s.Add("singleLine", settings.SingleLine);
            if (settings.AllowedClasses.Count == 0)
            {
                s.Add("allowedClasses", settings.AllowClasses);
            }
            else
            {
                string[] classes = new string[settings.AllowedClasses.Count];
                settings.AllowedClasses.CopyTo(classes, 0);
                s.Add("allowedClasses", classes);
            }

            if (settings.AllowedStyles.Count == 0)
            {
                s.Add("allowedStyles", settings.AllowStyles);
            }
            else
            {
                string[] styles = new string[settings.AllowedStyles.Count];
                settings.AllowedStyles.CopyTo(styles, 0);
                s.Add("allowedStyles", styles);
            }

            if (settings.AllowedTags.Count == 0)
            {
                s.Add("allowedTags", settings.AllowTags);
            }
            else
            {
                XmlRpcStruct array = GetAllowedTags(settings);
                s.Add("allowedTags", array);
            }

            s.Add("obfuscateEmail", settings.ObfuscateEmail);
            s.Add("mergeLines", settings.MergeLines);
            s.Add("blockModule.allowed.pre", settings.BlockModule.AllowedPre);
            s.Add("blockModule.allowed.text", settings.BlockModule.AllowedText);
            s.Add("blockModule.allowed.html", settings.BlockModule.AllowedHtml);
            s.Add("formatterModule.lineWrap", settings.FormatterModule.LineWrap);
            s.Add("formatterModule.indent", settings.FormatterModule.Indent);
            s.Add("headingModule.allowed.surrounded", settings.HeadingModule.AllowedSurrounded);
            s.Add("headingModule.allowed.underlined", settings.HeadingModule.AllowedUnderlined);
            s.Add("headingModule.top", settings.HeadingModule.Top);
            s.Add("headingModule.balancing", settings.HeadingModule.Balancing);
            s.Add("imageModule.root", settings.ImageModule.Root);
            s.Add("imageModule.linkedRoot", settings.ImageModule.LinkedRoot);
            s.Add("imageModule.leftClass", settings.ImageModule.LeftClass);
            s.Add("imageModule.rightClass", settings.ImageModule.RightClass);
            s.Add("imageModule.defaultAlt", settings.ImageModule.DefaultAlt);
            s.Add("imageDescModule.boxClass", settings.ImageDescriptionModule.BoxClass);
            s.Add("imageDescModule.leftClass", settings.ImageDescriptionModule.LeftClass);
            s.Add("imageDescModule.rightClass", settings.ImageDescriptionModule.RightClass);
            s.Add("linkModule.allowed.link", settings.LinkModule.AllowedLink);
            s.Add("linkModule.allowed.email", settings.LinkModule.AllowedEmail);
            s.Add("linkModule.allowed.url", settings.LinkModule.AllowedUrl);
            s.Add("linkModule.allowed.quickLink", settings.LinkModule.AllowedQuickLink);
            s.Add("linkModule.allowed.references", settings.LinkModule.AllowedReferences);
            s.Add("linkModule.root", settings.LinkModule.Root);
            s.Add("linkModule.emailOnClick", settings.LinkModule.EmailOnClick);
            s.Add("linkModule.imageOnClick", settings.LinkModule.ImageOnClick);
            s.Add("linkModule.popupOnClick", settings.LinkModule.PopupOnClick);
            s.Add("linkModule.forceNoFollow", settings.LinkModule.ForceNoFollow);
            s.Add("smiliesModule.allowed", settings.SmiliesModule.Allowed);
            s.Add("smiliesModule.root", settings.SmiliesModule.Root);
            s.Add("smiliesModule.class", settings.SmiliesModule.CssClass);
            s.Add("quoteModule.allowed.line", settings.QuoteModule.AllowedLine);
            s.Add("quoteModule.allowed.block", settings.QuoteModule.AllowedBlock);

            return s;
        }

        private static string AddReferences(string text, IList<Reference> references)
        {
            StringBuilder sb = new StringBuilder(text);
            foreach (Reference reference in references)
            {
                sb.AppendLine(reference.ToString());
            }
            return sb.ToString();
        }

        private static XmlRpcStruct GetAllowedTags(ITexySettings settings)
        {
            XmlRpcStruct array = new XmlRpcStruct();

            foreach (Tag tag in settings.AllowedTags)
            {
                if (tag.Attributes.Count > 0)
                {
                    string[] attributes = new string[tag.Attributes.Count];
                    tag.Attributes.CopyTo(attributes, 0);
                    array.Add(tag.Name, attributes);
                }
                else
                {
                    array.Add(tag.Name, true);
                }
            }
            return array;
        }
        #endregion

        #region TexyProvider Members
        /// <summary>
        /// Initialize
        /// </summary>
        /// <param name="name">Name</param>
        /// <param name="config">Config</param>
        public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
        {
            if (String.IsNullOrEmpty(config["serviceUrl"]))
            {
                config.Remove("serviceUrl");
                config.Add("serviceUrl", DefaultXmlRpcUrl);
            }

            base.Initialize(name, config);
            TexyConverter.Url = config["serviceUrl"];
        }

        /// <summary>
        /// Process
        /// </summary>
        /// <param name="text">Text</param>
        /// <param name="settings"></param>
        /// <returns>String</returns>
        public override string Process(string text, ITexySettings settings)
        {
            if (String.IsNullOrEmpty(text))
            {
                return String.Empty;
            }

            // pridame programove pridane reference
            text = AddReferences(text, settings.LinkModule.References);
            text = AddReferences(text, settings.ImageModule.References);

            // nastaveni konfigurace
            XmlRpcStruct configStruct = GetConfigurationStruct(settings);

            // převod stringu na base64
            byte[] buffer = Encoding.UTF8.GetBytes(text);
            // zavolání vzdálené metody
            buffer = TexyConverter.ToXhtml(buffer, configStruct);
            // převod base64 na string
            return Encoding.UTF8.GetString(buffer);
        }

        /// <summary>Vrací informace o verzi Texy!</summary>
        public override string Version
        {
            get { return TexyConverter.Version(); }
        }
        #endregion
    }
}
